package com.zt.questionnaire.common.config.redis;

import com.zt.questionnaire.common.utils.JsonUtils;
import com.zt.questionnaire.common.utils.SpringContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * redicache 工具类
 */
//@SuppressWarnings("unchecked")

@Slf4j
public class CacheOperator {

    @SuppressWarnings("rawtypes")
    @Autowired
    RedisTemplate redisTemplate;

    SpringContext context;

    public static int TIME_OUT = 15 * 24 * 60 * 60;

    /**
     * 锁的过期时间(单位：秒)
     */
    public static final long LOCK_EXPIRE_TIME = 30L;

    public int getTimeOut() {
        return TIME_OUT;
    }

    public void remove(String key) {
        redisTemplate.delete(key);
    }

    public void setObject(String key, Object value, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        ops.set(key, JsonUtils.toString(value));
        expire(key, expire);
    }

    public void setObject(String key, Object value) {
        setObject(key, value, 0);
    }

    public <T extends Object> T getObject(String key, Class<T> c, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        Object o = ops.get(key);
        if (o == null) {
            return null;
        }
        expire(key, expire);
        return JsonUtils.toObject(o.toString(), c);
    }

    public <T extends Object> T getObject(String key, Class<T> c) {
        return getObject(key, c, 0);
    }

    /**
     * 设置长整形,expire设置为0:表示无过期时间
     *
     * @param key
     * @param value
     * @param expire 按秒计时的过期时间
     */
    public void setLong(String key, long value, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        ops.set(key, value);
        expire(key, expire);
    }

    public void setLong(String key, long value) {
        setLong(key, value, 0);
    }

    public Long getLong(String key, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        Object o = ops.get(key);
        if (o == null) {
            return null;
        }
        expire(key, expire);
        return Long.parseLong(o.toString());
    }

    public Long getLong(String key) {
        return getLong(key, 0);
    }

    /**
     * 设置整型，expire设置为0:表示无过期时间
     *
     * @param key
     * @param value
     * @param expire
     */
    public void setInt(String key, int value, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        ops.set(key, value);
        expire(key, expire);
    }

    public void setInt(String key, int value) {
        setInt(key, value, 0);
    }

    public Integer getInt(String key, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        Object o = ops.get(key);
        if (o == null) {
            return null;
        }
        expire(key, expire);
        return Integer.parseInt(o.toString());
    }

    public Integer getInt(String key) {
        return getInt(key, 0);
    }

    public void setString(String key, String value, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        ops.set(key, value);
        expire(key, expire);
    }

    public void setString(String key, String value) {
        setString(key, value, 0);
    }

    public String getString(String key, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        Object o = ops.get(key);
        if (o != null) {
            expire(key, expire);
            return o.toString();
        }
        return null;
    }

    public String getString(String key) {
        return getString(key, 0);
    }

    public void setFloat(String key, float value, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        ops.set(key, value);
        expire(key, expire);
    }

    public void setFloat(String key, float value) {
        setFloat(key, value, 0);
    }

    public Float getFloat(String key, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        Object o = ops.get(key);
        if (o == null) {
            return null;
        }
        expire(key, expire);
        return Float.parseFloat(o.toString());
    }

    public Float getFloat(String key) {
        return getFloat(key, 0);
    }

    public void setDouble(String key, double value, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        ops.set(key, value);
        expire(key, expire);
    }

    public void setDouble(String key, double value) {
        setDouble(key, value, 0);
    }

    public Double getDouble(String key, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        Object o = ops.get(key);
        if (o == null) {
            return null;
        }
        expire(key, expire);
        return Double.parseDouble(o.toString());
    }

    public Double getDouble(String key) {
        return getDouble(key, 0);
    }

    public void setByte(String key, byte value, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        ops.set(key, value);
        expire(key, expire);
    }

    public void setByte(String key, byte value) {
        setByte(key, value, 0);
    }

    public Byte getByte(String key, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        Object o = ops.get(key);
        if (o == null) {
            return null;
        }
        expire(key, expire);
        return Byte.parseByte(o.toString());
    }

    public Byte getByte(String key) {
        return getByte(key, 0);
    }

    public void setShort(String key, short value, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        ops.set(key, value);
        expire(key, expire);
    }

    public void setShort(String key, short value) {
        setShort(key, value, 0);
    }

    public Short getShort(String key, long expire) {
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        Object o = ops.get(key);
        if (o == null) {
            return null;
        }
        expire(key, expire);
        return Short.parseShort(o.toString());
    }

    public Short getShort(String key) {
        return getShort(key, 0);
    }

    public <K, V extends Object> void setMap(String key, Map<K, V> value, Long expire) {
        if (value == null || value.size() == 0) {
            // 存放到redis里的map必须有值，否则抛异常
            return;
        }
        Map<String, String> map = new HashMap<>();
        HashOperations ops = redisTemplate.opsForHash();
        Set<K> keySet = value.keySet();
        for (K k : keySet) {
            V v = value.get(k);
            map.put(JsonUtils.toString(k), JsonUtils.toString(v));

        }
        ops.putAll(key, map);
        if (expire != null && expire > 0) {
            expire(key, expire);
        }
    }

    public <K, V extends Object> void setMap(String key, Map<K, V> value) {
        setMap(key, value, null);
    }

    public void setMapValue(String key, Object mapKey, Object mapValue, Long expire) {
        HashOperations ops = redisTemplate.opsForHash();
        ops.put(key, JsonUtils.toString(mapKey), JsonUtils.toString(mapValue));
        if (expire != null && expire > 0) {
            expire(key, expire);
        }
    }

    /**
     * 获取map的数量
     *
     * @param key
     * @return
     */
    public long getMapSize(String key, long expire) {
        HashOperations ops = redisTemplate.opsForHash();
        Long size = ops.size(key);
        if (size == null) {
            size = 0L;
        }
        expire(key, expire);
        return size;
    }

    /**
     * 当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param kClass
     * @param vClass
     * @return
     */
    public <K, V extends Object> Map<K, V> getMap(String key, Class<K> kClass, Class<V> vClass) {
        return getMap(key, kClass, vClass, null);
    }

    /**
     * 返回无序的map，当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param kClass
     * @param vClass
     * @param expire 有效时间，秒
     * @return
     */
    public <K, V extends Object> Map<K, V> getMap(String key, Class<K> kClass, Class<V> vClass, Long expire) {
        Map<K, V> map = new HashMap<>();
        HashOperations ops = redisTemplate.opsForHash();
        Map v = ops.entries(key);
        if (v != null) {
            Set keySet = v.keySet();
            for (Object k : keySet) {
                Object o = v.get(k);
                map.put(JsonUtils.toObject(k.toString(), kClass), JsonUtils.toObject(o.toString(), vClass));
            }
            if (expire != null && expire > 0) {
                expire(key, expire);
            }
        }

        return map;
    }

    public <T extends Object> T getMapValue(String key, Object mapKey, Class<T> valueType, long expire) {
        HashOperations ops = redisTemplate.opsForHash();
        Object v = ops.get(key, JsonUtils.toString(mapKey));
        if (v == null) {
            return null;
        }
        expire(key, expire);
        return JsonUtils.toObject(v.toString(), valueType);
    }

    public <T extends Object> T getMapValue(String key, Object mapKey, Class<T> valueType) {
        return getMapValue(key, mapKey, valueType, 0);
    }

    /**
     * 获取map的所有键集合，按照放入的先后顺序取出的，当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param c
     * @param expire
     * @return
     */
    public <K extends Object> List<K> getMapKeys(String key, Class<K> c, long expire) {
        List<K> list = new ArrayList<>();
        HashOperations ops = redisTemplate.opsForHash();
        Set keys = ops.keys(key);
        for (Object k : keys) {
            list.add(JsonUtils.toObject(k.toString(), c));
        }
        expire(key, expire);
        return list;
    }

    public boolean existMapKey(String key, Object mapKey) {
        HashOperations ops = redisTemplate.opsForHash();
        return ops.hasKey(key, mapKey.toString());
    }

    /**
     * 获取map的所有键集合，按照放入的先后顺序取出的，当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param c
     * @return
     */
    public <K extends Object> List<K> getMapKeys(String key, Class<K> c) {
        return getMapKeys(key, c, 0);
    }

    /**
     * 获取map的所有值集合，按照放入的先后顺序取出的，当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param c
     * @param expire
     * @return
     */
    public <V extends Object> List<V> getMapValues(String key, Class<V> c, Long expire) {
        List<V> list = new ArrayList<>();
        HashOperations ops = redisTemplate.opsForHash();
        List values = ops.values(key);
        for (Object k : values) {
            list.add(JsonUtils.toObject(k.toString(), c));
        }
        expire(key, expire);
        return list;
    }

    /**
     * 获取map的所有值集合，按照放入的先后顺序取出的， 当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param c
     * @return
     */
    public <V extends Object> List<V> getMapValues(String key, Class<V> c) {
        return getMapValues(key, c, null);
    }

    public void removeMapValue(String key, Object mapKey, long expire) {
        HashOperations ops = redisTemplate.opsForHash();
        ops.delete(key, JsonUtils.toString(mapKey));
        expire(key, expire);
    }

    public void removeMapValue(String key, Object mapKey) {
        removeMapValue(key, mapKey, 0);
    }

    public <T extends Object> void addList(String key, List<T> list, long expire) {
        if (list == null || list.size() == 0) {
            return;
        }
        List<String> list1 = new ArrayList<>();
        for (T obj : list) {
            if (obj != null) {
                list1.add(JsonUtils.toString(obj));
            }
        }
        if (list1.size() == 0) {
            return;
        }

        ListOperations ops = redisTemplate.opsForList();
        ops.rightPushAll(key, list1);
        expire(key, expire);
    }

    public <T extends Object> void addList(String key, List<T> list) {
        addList(key, list, 0);
    }

    /**
     * 当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param type
     * @param expire
     * @return
     */
    public <T extends Object> List<T> getList(String key, Class<T> type, long expire) {
        // -1表示最后一个元素
        return getList(key, type, 0, -1, expire);
    }

    /**
     * 当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param type
     * @return
     */
    public <T extends Object> List<T> getList(String key, Class<T> type) {
        return getList(key, type, 0);
    }

    /**
     * 获取list区间范围内的元素列表，当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param type
     * @param start  起始下标，从0开始，包含起始下标的值
     * @param end    结束下标，从0开始，包含结束下标的值
     * @param expire
     * @return
     */
    public <T extends Object> List<T> getList(String key, Class<T> type, long start, long end, long expire) {
        // -1表示最后一个元素
        ListOperations ops = redisTemplate.opsForList();
        List list = ops.range(key, start, end);
        List<T> re = new ArrayList<>();
        for (Object s : list) {
            re.add(JsonUtils.toObject(s.toString(), type));
        }
        expire(key, expire);
        return re;

    }

    /**
     * 获取list区间范围内的元素列表，当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param type
     * @param start 起始下标，从0开始，包含起始下标的值
     * @param end   结束下标，从0开始，包含结束下标的值,-1表示最后一个元素
     * @return
     */
    public <T extends Object> List<T> getList(String key, Class<T> type, long start, long end) {
        return getList(key, type, start, end, 0);
    }

    /**
     * 获取list的数量
     *
     * @param key
     * @return
     */
    public long getListSize(String key, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Long size = ops.size(key);
        if (size == null) {
            size = 0L;
        }
        expire(key, expire);
        return size;
    }

    /**
     * 在名称为key的list头添加一个值为value的 元素，当key不存在时创建key并写入value
     *
     * @param key
     * @param value
     * @return
     */
    public boolean addListValueFirst(String key, Object value, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Long n = ops.leftPush(key, JsonUtils.toString(value));
        expire(key, expire);
        return n == 0 ? false : true;
    }

    /**
     * 在名称为key的list头添加一个值为value的 元素，当key不存在时不添加
     *
     * @param key
     * @param value
     * @return
     */
    public boolean addListValueFirstKeyExsit(String key, Object value, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Long n = ops.leftPushIfPresent(key, JsonUtils.toString(value));
        expire(key, expire);
        return n == 0 ? false : true;
    }

    /**
     * 在名称为key的list尾部添加一个值为value的 元素
     *
     * @param key
     * @param value
     * @return
     */
    public boolean addListValueEnd(String key, Object value, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Long n = ops.rightPush(key, JsonUtils.toString(value));
        expire(key, expire);
        return n == 0 ? false : true;
    }

    /**
     * 在名称为key的list尾部添加一个值为value的 元素，当key不存在时不添加
     *
     * @param key
     * @param value
     * @return
     */
    public boolean addListValueEndKeyExsit(String key, Object value, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Long n = ops.rightPushIfPresent(key, JsonUtils.toString(value));
        expire(key, expire);
        return n == 0 ? false : true;
    }

    /**
     * 把元素存放到指定的位置，原来位置上的元素被覆盖掉（删除掉了）
     *
     * @param key
     * @param index  下标
     * @param value
     * @param expire
     */
    public void addListValue(String key, long index, Object value, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        ops.set(key, index, JsonUtils.toString(value));
        expire(key, expire);
    }

    /**
     * 获取指定下标的元素
     *
     * @param key    键
     * @param index  下标，从0开始，也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * @param type   返回元素对象的类型
     * @param expire 过期值
     * @return
     */
    public <T extends Object> T getListValue(String key, long index, Class<T> type, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Object obj = ops.index(key, index);
        if (obj == null) {
            return null;
        }
        T v = JsonUtils.toObject(obj.toString(), type);
        return v;
    }

    /**
     * 删除名称为key的list中的首元素
     *
     * @param key
     * @return
     */
    public boolean removeListValueFirst(String key, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Object obj = ops.leftPop(key);
        expire(key, expire);
        return obj == null ? false : true;
    }

    /**
     * 删除名称为key的list中的尾元素
     *
     * @param key
     * @return
     */
    public boolean removeListValueEnd(String key, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Object obj = ops.rightPop(key);
        expire(key, expire);
        return obj == null ? false : true;
    }

    /**
     * 删除名称为key的list中的value元素
     *
     * @param key
     * @param value
     * @param count count > 0 : 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。 count < 0 :
     *              从表尾开始向表头搜索，移除与 value 相等的元素，数量为 count 的绝对值。 count = 0 : 移除表中所有与
     *              value 相等的值。
     * @return
     */
    public boolean removeListValue(String key, Object value, int count, long expire) {
        ListOperations ops = redisTemplate.opsForList();
        Long obj = ops.remove(key, count, JsonUtils.toString(value));
        expire(key, expire);
        return obj == null ? false : true;
    }


    /**
     * 添加集合到 set
     *
     * @param key
     * @param list
     * @param expire 过期时间，null或者0，不设置过期时间
     * @param <T>
     */
    public <T extends Object> void addSet(String key, List<T> list, long expire) {
        if (ObjectUtils.isEmpty(list)) {
            return;
        }
        SetOperations ops = redisTemplate.opsForSet();
        for (T obj : list) {
            if (obj != null) {
                String value = JsonUtils.toString(obj);
                ops.add(ops, value);
            }
        }
        expire(key, expire);
    }

    /**
     * 添加集合到 set
     *
     * @param key
     * @param list
     * @param <T>
     */
    public <T extends Object> void addSet(String key, List<T> list) {
        addSet(key, list, 0);
    }

    /**
     * 添加单个值到set中
     *
     * @param key
     * @param value
     * @param expire 过期时间，null或者0，不设置过期时间
     * @return
     */
    public boolean addSetValue(String key, Object value, long expire) {
        SetOperations ops = redisTemplate.opsForSet();
        Long n = ops.add(key, JsonUtils.toString(value));
        expire(key, expire);
        return n != 0;
    }

    /**
     * 删除set中value值
     *
     * @param key
     * @param value
     * @param expire 过期时间，null或者0，不设置过期时间
     * @return
     */
    public boolean removeSetValue(String key, Object value, long expire) {
        SetOperations ops = redisTemplate.opsForSet();
        Long n = ops.remove(key, JsonUtils.toString(value));
        expire(key, expire);
        return n != 0;
    }

    /**
     * 删除set中多个值
     *
     * @param key
     * @param list
     * @param expire 过期时间，null或者0，不设置过期时间
     * @return
     */
    public boolean removeSet(String key, List<Object> list, long expire) {
        if (ObjectUtils.isEmpty(list)) {
            return true;
        }
        SetOperations ops = redisTemplate.opsForSet();
        for (Object obj : list) {
            if (obj != null) {
                String value = JsonUtils.toString(obj);
                ops.remove(ops, value);
            }
        }
        expire(key, expire);
        return true;
    }

    /**
     * 当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param type
     * @return
     */
    public <T extends Object> List<T> getSet(String key, Class<T> type) {
        return getSet(key, type, 0);
    }

    /**
     * 获取set所有元素，当key不存在时，返回的集合大小为0，不会返回null
     *
     * @param key
     * @param type
     * @param expire
     * @return
     */
    public <T extends Object> List<T> getSet(String key, Class<T> type, long expire) {
        // -1表示最后一个元素
        List<T> list = new ArrayList<>();
        SetOperations ops = redisTemplate.opsForSet();
        Set set = ops.members(key);
        for (Object s : set) {
            list.add(JsonUtils.toObject(s.toString(), type));
        }
        expire(key, expire);
        return list;
    }

    /**
     * 获取sortSet数量
     *
     * @param key
     * @param expire null表示不设置过期时间,永不过期
     * @return
     */
    public long getSortSetSize(String key, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        Long size = ops.zCard(key);
        if (size == null) {
            size = 0L;
        }
        if (expire != null) {
            expire(key, expire);
        }
        return size;
    }

    /**
     * 获取排序set里的元素,按照递增排序，如果想按照递减排序，添加的时候，score给负数
     *
     * @param key
     * @param start  起始位置，0开始
     * @param end    结束为止，-1表示全部（包含结束位置）
     * @param expire null表示不设置过期时间,永不过期
     * @return
     */
    public <T extends Object> List<T> getSortSet(String key, long start, long end, Class<T> c, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        Set set = ops.range(key, start, end);
        List<T> re = new ArrayList<>();
        for (Object s : set) {
            re.add(JsonUtils.toObject(s.toString(), c));
        }
        expire(key, expire);
        return re;
    }

    /**
     * 获取所有的值,按照递增排序，如果想按照递减排序，添加的时候，score给负数
     *
     * @param key
     * @param c
     * @param expire null表示不设置过期时间,永不过期
     * @return
     */
    public <T extends Object> List<T> getSortSet(String key, Class<T> c, Long expire) {
        return getSortSet(key, 0, -1, c, expire);
    }

    /**
     * 获取值在sortSet集合里的排序位置，从0开始。本方法可以用来判断值是否存在集合里面
     *
     * @param key
     * @param v
     * @param expire
     * @return 排序，null表示值不存在
     */
    public Long getSortSetSort(String key, Object v, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        Long sort = ops.rank(key, v);
        return sort;
    }

    /**
     * 获取集合最后一位的score（排序分值）
     *
     * @param key
     * @param c      score的类型
     * @param expire
     * @return null表示没有数据
     */
    public <T extends Object> Double getSortSetScoreLast(String key, Class<T> c, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        Set set = ops.rangeWithScores(key, -1, -1);
        if (set != null && set.size() == 1) {
            Iterator iterator = set.iterator();
            TypedTuple score = (TypedTuple) iterator.next();
            return score.getScore();
        }
        return null;
    }

    /**
     * 获取集合第一位的score（排序分值）
     *
     * @param key
     * @param c      score的类型
     * @param expire
     * @return null表示没有数据
     */
    public <T extends Object> Double getSortSetScoreFirst(String key, Class<T> c, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        Set set = ops.rangeWithScores(key, 0, 0);
        if (set != null && set.size() == 1) {
            Iterator iterator = set.iterator();
            TypedTuple score = (TypedTuple) iterator.next();
            return score.getScore();
        }
        return null;
    }

    public long getSortSetCard(String key) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        long n = ops.zCard(key);
        return n;
    }

    /**
     * 添加元素到有序集合（sortSet）里面
     *
     * @param key
     * @param score 可以是整数值或双精度浮点数，按照递增排序，如果想按照递减排序，score给负数
     * @param value
     */
    public void addSortSetValue(String key, Number score, Object value, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        ops.add(key, JsonUtils.toString(value), score.doubleValue());
        if (expire != null) {
            expire(key, expire);
        }
    }

    /**
     * 为有序集 key 的成员 value 的 score 值加上增量 inscreScore,可以通过传递一个负数值 inscreScore ，让 score
     * 减去相应的值
     *
     * @param key
     * @param inscreScore
     * @param value
     */
    public void increSortSetValue(String key, Number inscreScore, Object value, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        ops.incrementScore(key, JsonUtils.toString(value), inscreScore.doubleValue());
        if (expire != null) {
            expire(key, expire);
        }
    }

    /**
     * 添加元素到有序集合（sortSet）里面
     *
     * @param key
     * @param scoreValue [socre,value,socre,value.....]
     * @throws Exception
     */
    public <T extends Object> void addSortSetValue(String key, List<T> scoreValue, Long expire) throws Exception {
        ZSetOperations ops = redisTemplate.opsForZSet();
        Set<TypedTuple> set = new HashSet<>();
        int size = scoreValue.size();
        if (size % 2 != 0) {
            throw new Exception("scoreValue必须成对出现");
        }
        for (int i = 0; i < size; i += 2) {
            T score = scoreValue.get(i);
            if (!(score instanceof Number)) {
                throw new Exception("score必须为数字类型");
            }
            T value = scoreValue.get(i + 1);
            TypedTuple obj = new DefaultTypedTuple(JsonUtils.toString(value), ((Number) score).doubleValue());
            set.add(obj);
        }
        ops.add(key, set);
        if (expire != null) {
            expire(key, expire);
        }

    }

//	public <T extends Object> void addSortSetValue1(String key,List<T> scoreValue,long expire) throws Exception{
//		ZSetOperations ops = redisTemplate.opsForZSet();
//		int size = scoreValue.size();
//		if(size % 2 != 0){
//			throw new Exception("scoreValue必须成对出现");
//		}
//		for (int i=0;i<size;i+=2) {
//			T score = scoreValue.get(i);
//			if(!(score instanceof Number)){
//				throw new Exception("score必须为数字类型");
//			}
//			T value = scoreValue.get(i+1);
//			ops.add(key,RedisUtils.toString(value), ((Number)score).doubleValue());
//		}
//		expire(key, expire);
//
//	}

    public void removeSortSetValue(String key, Object value, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        ops.remove(key, JsonUtils.toString(value));
        if (expire != null) {
            expire(key, expire);
        }
    }

    public <T extends Object> void removeSortSetValue(String key, List<T> value, Long expire) {
        int i = 0;
        Object[] objs = new Object[value.size()];
        for (Object obj : value) {
            objs[i++] = JsonUtils.toString(obj);
        }
        ZSetOperations ops = redisTemplate.opsForZSet();
        ops.remove(key, objs);
        if (expire != null) {
            expire(key, expire);
        }
    }

    public void removeSortSetValue(String key, int startIndex, int endIndex, Long expire) {
        ZSetOperations ops = redisTemplate.opsForZSet();
        ops.removeRange(key, startIndex, endIndex);
        if (expire != null) {
            expire(key, expire);
        }
    }

    /**
     * 递增数值
     *
     * @param key
     * @param incrNum 要增加或减少的数值，正负表示加减
     * @param expire
     * @return 修改后的最终结果
     */
    public Long increment(String key, long incrNum, long expire) {
        ValueOperations ops = redisTemplate.opsForValue();
        Long v = ops.increment(key, incrNum);
        expire(key, expire);
        return v;
    }

    public void increment(String key, double incrNum, long expire) {
        ValueOperations ops = redisTemplate.opsForValue();
        ops.increment(key, incrNum);
        expire(key, expire);
    }

    /**
     * 批量删除key
     *
     * @param pattern 表达式，* 表示删除所有的键，不支持集群
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }

    /**
     * 判断缓存中是否有对应的value
     *
     * @param key NOT NULL
     * @return
     */
    public boolean isExists(final String key) {
        return redisTemplate.hasKey(key);
    }

    public void expire(String key, Long seconds) {
        if (seconds == null || seconds <= 0) {
            return;
        }
        redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
    }

    /**
     * 向指定的通道发送数据
     *
     * @param channel
     * @param message
     */
    public void sendChannelMess(String channel, String message) {
        redisTemplate.convertAndSend(channel, message);
    }

    public void sendChannelMess(String channel, Object message) {
        redisTemplate.convertAndSend(channel, message);
    }

    /**
     * 发送者发布消息
     *
     * @param channel
     * @param message
     */
    public void publish(String channel, Object obj) {
        log.info("发布redis订阅消息，channel={}，msg={}", channel, obj);
        sendChannelMess(channel, JsonUtils.toString(obj));
//		log.info("发布redis订阅消息，channel={}，msg={}",channel,obj);
    }

    /**
     * 订阅者订阅消息
     *
     * @param channel  通道名称
     * @param listener 订阅事件
     */
    public void subscribe(String channel, MessageListener listener) {
        log.info("初始化订阅消息={}", listener.getClass());
        RedisMessageListenerContainer container = context.getBean(RedisMessageListenerContainer.class);
        container.addMessageListener(listener, new ChannelTopic(channel));
    }

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    /**
     * 尝试获取分布式锁（即设置一个一个标识到redis里，说明有线程正在处理相关的逻辑，处理完后，删除即标识锁被释放），
     * 如果锁没有被其他线程占用则返回true，否则返回false，返回false的时候，调用的地方要等待稍后再获取
     *
     * @param key        锁对象，每块需要加锁的地方都有单独的一个锁对象
     * @param value      值，每次获取的时候给的值最好都是随机的，释放锁的时候验证，值一样才释放，
     *                   避免拿到锁后，逻辑执行时间太长，锁自己超时了，其他的线程又已经获取到锁后，被这里给释放掉了
     * @param expireTime 过期时间，默认为5秒，避免执行逻辑出现错误，锁没有被释放
     * @return
     */
    public boolean getLock(String key, Object value, Long expireTime) {
        if (expireTime == null) {
            // 避免执行逻辑出现错误，锁没有被释放
            expireTime = 5L;
        }
        ValueOperations<Serializable, Object> ops = redisTemplate.opsForValue();
        // 当键不存在时才设置,设置成功就说明拿到了锁对象，原子操作
        Boolean result = ops.setIfAbsent(key, value);
        expire(key, expireTime);
        if (result != null && result) {
            return true;
        }
        return false;

    }

    /**
     * 尝试获取锁，如果获取不到就卡住
     *
     * @param key
     * @param vlaue
     * @param expireTime
     * @return
     */
    public boolean tryLock(String key, Object value, Long expireTime) {
        boolean isLock = false;
        do {
            isLock = getLock(key, value, expireTime);
        } while (!isLock);
        return isLock;
    }

    /**
     * 释放分布式锁,锁使用完成后要释放掉（这里就是删除）
     *
     * @param key   锁对象，每块需要加锁的地方都有单独的一个锁对象
     * @param value 值，每次获取的时候给的值最好都是随机的，释放锁的时候验证，值一样才释放，
     *              避免拿到锁后，逻辑执行时间太长，锁自己超时了，其他的线程又已经获取到锁后，被这里给释放掉了
     * @return
     */
    public boolean unlock(String key, Object value) {
        // redis执行lua脚本，实现原子操作，这里做的是检查键是否存在，且值和value相同，就删除键，表示锁被释放
        String scriptStr = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        RedisScript<Boolean> script = new DefaultRedisScript<>(scriptStr, Boolean.class);

        Boolean result = (Boolean) redisTemplate.execute(script, Collections.singletonList(key), value);
        if (result != null && result) {
            return true;
        }
        return false;

    }

//
//
//
//
//	@SuppressWarnings("unchecked")
//	public <T extends Object> T getObject(String key, Class<T> c, Long expire) {
//		Object o = getObj(key, expire);
//		return  (T) o;
//	}
//
//	public Object getObj(String key, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		Object o = ops.get(key);
//		if(o == null){
//			return null;
//		}
//		expire(key, expire);
//		return  o;
//	}
//
//
//
//	/**
//	 * 设置长整形,expire设置为0:表示无过期时间
//	 *
//	 * @param key
//	 * @param value
//	 * @param expire
//	 *            按秒计时的过期时间
//	 */
//	public void setLong(String key, long value, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		ops.set(key, value);
//		expire(key, expire);
//	}
//
//
//	public Long getLong(String key, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		Object o = ops.get(key);
//		if(o == null){
//			return null;
//		}
//		expire(key, expire);
//		return Long.parseLong(o.toString());
//	}
//
//
//	/**
//	 * 设置整型，expire设置为0:表示无过期时间
//	 *
//	 * @param key
//	 * @param value
//	 * @param expire
//	 */
//	public void setInt(String key, int value, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		ops.set(key, value);
//		expire(key, expire);
//	}
//
//
//	public Integer getInt(String key, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		Object o = ops.get(key);
//		if(o == null){
//			return null;
//		}
//		expire(key, expire);
//		return Integer.parseInt(o.toString());
//	}
//
//
//	public void setString(String key, String value, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		ops.set(key, value);
//		expire(key, expire);
//	}
//
//
//	public String getString(String key, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		Object o = ops.get(key);
//		if(o != null) {
//			expire(key, expire);
//			return o.toString();
//		}
//		return null;
//	}
//
//
//	public void setFloat(String key, float value, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		ops.set(key, value);
//		expire(key, expire);
//	}
//
//
//	public Float getFloat(String key, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		Object o = ops.get(key);
//		if(o == null){
//			return null;
//		}
//		expire(key, expire);
//		return Float.parseFloat(o.toString());
//	}
//
//
//	public void setDouble(String key, double value, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		ops.set(key, value);
//		expire(key, expire);
//	}
//
//
//	public Double getDouble(String key, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		Object o = ops.get(key);
//		if(o == null){
//			return null;
//		}
//		expire(key, expire);
//		return Double.parseDouble(o.toString());
//	}
//
//
//	public void setByte(String key, byte value, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		ops.set(key, value);
//		expire(key, expire);
//	}
//
//
//	public Byte getByte(String key, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		Object o = ops.get(key);
//		if(o == null){
//			return null;
//		}
//		expire(key, expire);
//		return Byte.parseByte(o.toString());
//	}
//
//
//	public void setShort(String key, short value, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		ops.set(key, value);
//		expire(key, expire);
//	}
//
//
//	public Short getShort(String key, Long expire) {
//		ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//		Object o = ops.get(key);
//		if(o == null){
//			return null;
//		}
//		expire(key, expire);
//		return Short.parseShort(o.toString());
//	}
//
//
//	/**
//	 * 获取map的数量
//	 * @param key
//	 * @return
//	 */
//	public long getMapSize(String key,Long expire){
//		HashOperations<String, Object, Object> ops = redisTemplate.opsForHash();
//		Long size = ops.size(key);
//		if(size == null){
//			size = 0L;
//		}
//		expire(key, expire);
//		return size;
//	}
//

}
